#from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
import logging

from StringIO import StringIO                                                  
import traceback
import xmlrpclib
from xmlrpcserver import XmlRpcServer

from models import api
from models import gamebase
       
class MultiCallXmlRpcServer(XmlRpcServer):
    def __init__(self, *args, **kwds):
        XmlRpcServer.__init__(self, *args, **kwds)
        self.register('system.multicall', self.system_multiCall)
 
    def system_multiCall(self, meta, methods):
        """Implements the xmlrpc Multi call functionality"""

        results=[]

        for m in methods:
            rpccall=m['methodName']
            params=m['params']
            results.append([self.resolve(rpccall)(meta, *params)])

        return results
        
class XmlRpcWrapper():
    """
    This class acts as a wrapper around a python object. It copies
    the underlying objects methods so they can be made avaliable to the XmlRpcServer class
    If the methods are public, the first argument "meta" is stripped off of the call from the 
    XMLRpcServer object, so that we can use a generic underlying object for the api call. 
    Private methods (i.e. those starting with an "_" are copied as is, as they are not exposed as
    remote procedures
    """
    def __init__(self, obj):
        self._obj=obj
        for a in dir(obj):
            m=getattr(obj, a)
            if callable(m) and a[0]!="_":
                    self.__dict__[a] = self._call_api_method(a)
                    self.__dict__[a].__doc__ = m.__doc__
                                
    def _call_api_method(self, method):
        return lambda meta, *args, **kwds: getattr(self._obj, method)(*args, **kwds)
             
class XMLRpcHandler(webapp.RequestHandler):                        
    rpcserver = None
                                
    def __init__(self):         
        self.rpcserver = MultiCallXmlRpcServer()
        self.rpcserver.register_class('gamemanager',XmlRpcWrapper(api.GameManager()))
        self.rpcserver.register_class('playinfo',XmlRpcWrapper(api.PlayInfo()))
        self.rpcserver.register_class('playmanager',XmlRpcWrapper(api.PlayManager()))
        
    def post(self):
        response = StringIO()
        api_version= self.request.headers["X-Endeavor-Api-Version"] if "X-Endeavor-Api-Version" in self.request.headers.keys() else "None"                                        
        if api_version != api.API_VERSION:
            response.write(
                xmlrpclib.dumps(xmlrpclib.Fault
                                (-1000, "API Version Mismatch, client must be running api version %s, got %s. Download the latest client from http:code.google.com/p/endeavorserver/" % 
                                (api.API_VERSION, api_version)),
                                 methodresponse = True)
            )        
        else:
            request=StringIO(self.request.body)
            request.seek(0)                                                        
            try:
                self.rpcserver.execute(request, response, None)
            except gamebase.GameException, e:
                #If we have a "normal" API error, replace the generic xmlrpclib error message
                #With our more meaningful one
                response=StringIO()
                response.write(
                    xmlrpclib.dumps(xmlrpclib.Fault
                                    (e.code, e.message),
                                    methodresponse = True))        
            except Exception, e:                                                   
                logging.error('Error executing: '+str(e))                          
                for line in traceback.format_exc().split('\n'):                    
                    logging.error(line)

        response.seek(0)                                                                         
        rstr = response.read()
        self.response.headers['Content-type'] = 'text/xml'                     
        self.response.headers['Content-length'] = "%d"%len(rstr)               
        self.response.out.write(rstr)

# add a handler for XMLRPC calls
application = webapp.WSGIApplication(
                                     [('/xmlrpc/.*', XMLRpcHandler)
                                     ],
                                     debug=True
                                    )

def profile_main():
    # This is the main function for profiling
    # We've renamed our original main() above to real_main()
    import cProfile, pstats, StringIO
    prof = cProfile.Profile()
    prof = prof.runctx("real_main()", globals(), locals())
    stream = StringIO.StringIO()
    stats = pstats.Stats(prof, stream=stream)
    stats.sort_stats("time")  # Or cumulative
    stats.print_stats(80)  # 80 = how many to print

    # The rest is optional.

    # stats.print_callees()

    # stats.print_callers()

    logging.info("Profile data:\n%s", stream.getvalue())

def real_main():
    run_wsgi_app(application)

main=real_main

if __name__ == "__main__":
    main()
